<template>
  <div>
    <el-row class="statistics-section page-section conversition">
      <div class="page-title">会话</div>
      <el-col :span="4" v-if="testBuild">
        <div class="border-box">
          <span class="limit-label">客服名称：</span>
          <input
            class="limit-input"
            v-model.trim="inputId"
            @blur="setId(inputId)"
            :disabled="disableInput"
          />
        </div>
      </el-col>
      <el-col :span="6">
        <div class="border-box">
          <span class="limit-label">最大接待人数：</span>
          <input
            class="limit-input"
            v-model.trim="limitPerson"
            @keydown.13="setLimit"
          />
        </div>
      </el-col>
      <el-col :span="2"
        ><span>接起会话数：</span><span>{{ connectTotal }}</span></el-col
      >
      <el-col :span="2"
        ><span>结束会话数：</span
        ><span>{{ connectTotal - selecetUserNum }}</span></el-col
      >
      <el-col :span="4"
        ><span>在线时长：</span><span>{{ showTime }}</span></el-col
      >
    </el-row>
    <div class="main-cover">
      <div class="inner-list">
        <inner-list></inner-list>
      </div>
      <div class="chat-panel">
        <chat-panel @send="send" :recieve="recieve"></chat-panel>
      </div>
      <div class="right-menu">
        <rigth-menu></rigth-menu>
      </div>
    </div>
  </div>
</template>

<script>
import InnerList from "./components/inner-list";
import rigthMenu from "./components/right-menu";
import chatPanel from "./components/chat-panel";
import { enterBig, connectWS, getMaxNum, setMaxNum } from "@/api/chat";
import { mapMutations, mapState, mapGetters } from "vuex";
import {
  wsSend,
  transMessage,
  transLinkMessage,
  transCommentMessage,
} from "./utils";
import { SmartMeeting } from "./model/smartMeeting";

export default {
  name: "conversation",
  components: {
    InnerList,
    rigthMenu,
    chatPanel,
  },
  data() {
    return {
      inputId: "",
      disableInput: false,
      ID: "",
      bigMeetingId: "",
      bigWsTask: {},
      bigOpen: false,
      meetingObj: {},
      meetingId: "", //当前小会场id沙发客
      memberId: "", //当前用户id
      timeout: 4000, //心跳信息响应时间
      interval: 8000, //发心跳间隔时间
      clientTimer: null,
      severTimer: null,
      recieve: {},
      updataList: {},
      reconnectNum: 0,
      reconnectLimit: 5,
      waiterName: "",
      waiterType: "",
      messageObj: null,
      onlinComplete: false,
      limitPerson: null,
      testBuild: "",
    };
  },
  computed: {
    ...mapState([
      "currentChat",
      "selecetUserList",
      "selectUser",
      "meetings",
      "showTime",
      "connectTotal",
      "currentCloseMeetingId",
      "idStore",
    ]),
    ...mapGetters(["selecetUserNum"]),
  },
  watch: {
    bigMeetingId() {
      if (this.bigMeetingId && this.ID) {
        this.enterBigMeeting();
      }
    },
    "currentChat.meetingId": {
      handler(newVal) {
        //切换当前聊天对象的id
        this.meetingId = newVal;
        this.meetingObj = this.meetings.get(`ws${newVal}`); //找出当前链路
        //  if(this.meetingObj.unconnect){ //如果已断开这重连
        //    this.meetingObj.createWs()
        //  }
      },
    },
    selectUser: {
      handler(newVal) {
        const meeting = this.meetings.get(`ws${newVal.meetingId}`);
        meeting.createWs(); //创建小会场ws
        meeting.wsTask.addEventListener("message", (e) => {
          this.onMessage(e, meeting);
        });
      },
      deep: true,
    },
    currentCloseMeetingId(val) {
      //关闭对应的会场
      const meeting = this.meetings.get(`ws${val}`);
      if (meeting.wsTask && meeting.open) {
        //用户没下线，客服主动关闭
        // meeting.wsTask.send({ content: "客服关闭当前用户", type: "0x65" });
        const params = {
          type: "0x65",
          content: "客服关闭当前用户",
        };
        wsSend(meeting.wsTask, params);
        // 下一步的关闭会场逻辑在监听消息之后完成
      } else {
        //用户已下线，客服关闭
        const params = {
          type: "del",
          meetingId: val,
        };
        this.updateMeeting(params);
      }
    },
    reconnectNum(val) {
      if (val === 0 && this.messageObj) {
        this.messageObj.close();
      }
      if (val && !this.messageObj) {
        this.messageObj = this.$message({
          type: "error",
          message: "通讯异常，重新连接中...",
          center: true,
          duration: 0,
        });
      }
    },
  },
  created() {
    this.testBuild = process.env.VUE_NODE_ENV === "test" ? true : false;
  },
  mounted() {
    let ifrs = window.parent.document.getElementsByTagName("iframe");
    for (let i = 0, j = ifrs.length; i < j; i++)
      if (ifrs[i].contentWindow == window) {
        const index1 = ifrs[i].src.lastIndexOf("/");
        const index12 = ifrs[i].src.indexOf("?");
        let pageName = ifrs[i].src.slice(index1, index12);
        let userName = ifrs[i].src.replace(/.*loginName=/, "");
        if (pageName == "/conversation") {
          this.setId(userName);
        } else {
          this.setIdStore({
            waiterId: userName,
            waiterName: userName,
            waiterType: 1,
          });
        }
        break;
      }
  },
  methods: {
    ...mapMutations([
      "setUserList",
      "updateState",
      "setIdStore",
      "updateMeeting",
      "updateSelecetUserList",
      "updateSelecetUserListSate",
      "setSmartConcatInfo",
      "setConnectTotal",
      "setCurrentChat",
    ]),
    // 设置接待人数
    async getLimit() {
      if (!this.ID) {
        return;
      }
      const params = {
        token: this.ID,
      };
      await getMaxNum(params)
        .then((res) => {
          this.limitPerson = res.data;
        })
        .catch(() => {
          this.$message.error("获取最大接待人数异常");
        });
    },
    // 设置接待人数
    setLimit() {
      const limitNum = Number(this.limitPerson);
      if (isNaN(limitNum) || limitNum < 3 || limitNum > 10) {
        this.$message.warning("请设置3至10之间的数字");
        this.limitPerson = null;
        return;
      }
      const params = {
        token: this.ID,
        connectionNum: this.limitPerson,
      };
      setMaxNum(params)
        .then(() => {
          this.$message.success("设置成功");
        })
        .catch(() => {
          this.$message.error("设置最大接待人数异常");
        });
    },
    async setId(waiterName) {
      // if (!this.inputId && !this.idStore.waiterName) {
      //   this.$message.warning('获取用户信息！')
      //   return;
      // }
      if (!waiterName) {
        this.$message.warning("未获取用户信息！");
        return;
      }
      this.waiterName = waiterName;
      this.inputId = waiterName;
      this.disableInput = true;
      await this.toBigMeeting();
      await this.getLimit();
    },
    //获取大会场id
    async toBigMeeting() {
      const params = {
        username: this.waiterName,
        type: 1,
      };
      await enterBig(params)
        .then((res) => {
          const { code, data, desc } = res;
          if (code != 200) {
            this.$message.warning(desc);
            return;
          }
          this.bigMeetingId = data.mainId;
          this.ID = data.token;
          this.waiterType = data.userType;
          this.setIdStore({
            bigMeetingId: this.bigMeetingId,
            waiterId: this.ID,
            waiterName: this.waiterName,
            waiterType: this.waiterType,
          });
        })
        .catch(() => {
          this.$message.error(`进入大会场异常`);
        });
    },
    // ws连接大会场
    async enterBigMeeting() {
      const s = `?talkerType=1&talkerId=${this.ID}&meetingId=${this.bigMeetingId}`;
      this.bigWsTask = await connectWS(s);
      this.wsListenter();
    },
    wsListenter() {
      this.bigWsTask.addEventListener("open", () => {
        this.bigOpen = true;
        this.reconnectNum = 0;
        this.updateSelecetUserList({ type: "clear" });
        this.updateMeeting({ type: "clear" });
        this.heartStart();
        console.log("连接上了");
      });
      this.bigWsTask.addEventListener("message", (e) => {
        this.heartStart();
        let { data } = e;
        let { type, content } = JSON.parse(data);
        if (type === "0x20") {
          this.setSmartConcatInfo(content);
        }
        if (type === "0x59") {
          //刷新时返回存活的用户
          const params = { type: "set", num: content.length };
          this.setConnectTotal(params);
          content.forEach((element) => {
            this.concatSmartMeeting(element);
          });
        }
        if (type === "0x66") {
          const addData = { type: "add", num: content.length };
          this.setConnectTotal(addData);
          const meetingId = content.smallMeetingId;
          const memberId = content.memberId;
          const memberType = content.memberType;
          let memberName = content.memberNikeName || "";
          memberName =
            memberType == 4 ? "游客" + memberId.slice(-4) : memberName;
          const userPhone = content.userPhone || "";
          const clientId = content.clientId || "";
          //自动分配用户
          const s = `?talkerType=${this.waiterType}&talkerId=${this.ID}&meetingId=${meetingId}&otherId=${memberId}`;
          const meetingInstantce = new SmartMeeting(s, meetingId); //创建一个小会场ws实例
          meetingInstantce.createWs(); //创建小会场ws
          meetingInstantce.wsTask.addEventListener("message", (e) => {
            this.onMessage(e, meetingInstantce);
          });
          // 将meeting实例放入store中
          const params = {
            type: "add",
            key: `ws${meetingId}`,
            value: meetingInstantce,
          };
          this.updateMeeting(params); //更新mettingMap列表
          let userInfo = {
            meetingId,
            offline: false,
            active: false,
            unread: 0,
            lastTxt: "",
            lastTime: "",
            memberId,
            nikeName: memberName,
            userType: memberType,
            userPhone: userPhone,
            clientId: clientId,
          };
          const isHas = this.selecetUserList.some(
            (user) => user.meetingId === meetingId
          );
          if (isHas) {
            delete userInfo.active;
            delete userInfo.unread;
            delete userInfo.lastTxt;
            delete userInfo.lastTime;
            this.updateSelecetUserListSate({ type: "reset", ...userInfo });
          } else {
            this.updateSelecetUserList({ type: "add", ...userInfo }); // 更新选中的列表
          }
        }
      });
      this.bigWsTask.addEventListener("close", () => {
        this.bigOpen = false;
        console.log("关闭了");
      });
    },
    heartStart() {
      this.serverTimer && clearTimeout(this.serverTimer);
      this.clientTimer && clearInterval(this.clientTimer);
      this.clientTimer = setInterval(() => {
        //发送消息，服务端返回信息，即表示连接良好，可以在socket的onmessage事件重置心跳机制函数
        this.bigSend({ content: "", type: "0x25" });
        //定义一个延时器等待服务器响应，若超时，则关闭连接，重新请求server建立socket连接
        this.serverTimer && clearTimeout(this.serverTimer);
        this.serverTimer = setTimeout(() => {
          this.bigWsTask.close();
          if (this.selecetUserList.length) {
            this.selecetUserList.forEach((user) => {
              const meeting = this.meetings.get(`ws${user.meetingId}`);
              meeting.wsTask.close();
            });
          }
          this.reConnect();
          this.serverTimer && clearTimeout(this.serverTimer);
        }, this.timeout);
      }, this.interval);
    },
    reConnect() {
      if (this.reconnectNum >= this.reconnectLimit) {
        this.serverTimer && clearTimeout(this.serverTimer);
        this.clientTimer && clearInterval(this.clientTimer);
        this.reconnectNum = 0;
        this.$alert("通讯异常，连接失败", "提示", {
          confirmButtonText: "确定",
          callback: () => {
            window.location.reload();
          },
        });
        return;
      }
      this.reconnectNum++;
      this.enterBigMeeting();
    },
    bigSend(data) {
      if (!this.bigOpen) {
        // throw '大会场未连接'
        return;
      }
      //发送消息，
      const params = {
        type: data.type,
        content: data.content,
      };
      wsSend(this.bigWsTask, params);
    },
    send(data) {
      if (!this.meetingObj.open) {
        // throw '小会场未连接'
        return;
      }
      let type = null;
      if (data.type === "heart") type = "0x25";
      if (data.type === "text") type = "0x40";
      if (data.type === "img") type = "0x44";
      if (data.type === "link") type = "0x62";
      if (data.type === "incoming") type = "0x27";
      if (data.type === "comecompelet") type = "0x28";
      //发送消息，
      const params = {
        type,
        content: data.content,
      };
      const res = wsSend(this.meetingObj.wsTask, params);
      res && this.$message.warning("发送ws消息，必填参数未传");
    },
    /*小会场读取所有ws的方法*/
    onMessage(e, meeting) {
      let { data } = e;
      const message = JSON.parse(data);
      if (
        message.type === "0x26" ||
        message.type === "0x29" ||
        message.type === "0x33" ||
        message.type === "0x34" ||
        message.type === "0x65"
      ) {
        let tip = "";
        if (message.type === "0x26") tip = "用户静待超时";
        if (message.type === "0x29") tip = "用户退出页面";
        if (message.type === "0x33") tip = "用户下线";
        if (tip) {
          this.$message({
            type: "warning",
            duration: 3000,
            message: `${message.content.talkerName || ""}${tip}，已离开了会话`,
          });
        }
        // const data = {
        //   type: "offline",
        //   meetingId: meeting.meetingId,
        // };
        // this.updateSelecetUserListSate(data);
        if (meeting.meetingId == this.currentChat.meetingId) {
          // this.$message({
          //   type:'warning',
          //   duration:0,
          //   message:'用户退出',
          //   showClose:true,
          //   offset:300
          // })
          this.setCurrentChat({});
        }
        meeting.wsTask.close();
        const params = {
          type: "del",
          meetingId: meeting.meetingId,
        };
        this.updateSelecetUserList(params);
        this.updateMeeting(params);
      }
      if (message.type === "0x78") {
        //后端发送（两人都上线）
        const automsg = {
          //客服发欢迎辞
          type: "0x79",
          content: "尊敬的用户，很高兴为您服务，请问有什么可以帮到您？",
        };
        wsSend(meeting.wsTask, automsg);
      }
      if (message.type === "0x41" || message.type === "0x79") {
        let msg = transMessage(message);
        //对方说的话
        if (message.content.talkerId != this.ID) {
          //添加未读图标
          if (this.meetingId != meeting.meetingId) {
            const data = {
              type: "unread",
              meetingId: meeting.meetingId,
            };
            this.updateSelecetUserListSate(data);
          } else {
            const params = {
              type: 0, //文字|图片|语音|工具连接
              from: 1, //0自己||1对方
            };
            this.recieve = { ...msg, ...params };
          }
        } else {
          //自己说的话
          const params = {
            type: 0, //文字|图片|语音|工具连接|评价消息
            from: 0, //0自己||1对方
          };
          if (this.meetingId == meeting.meetingId) {
            this.recieve = { ...msg, ...params };
          }
        }
        //添加最后一条消息
        const data = {
          type: "text",
          meetingId: meeting.meetingId,
          lastTxt: msg.content,
          lastTime: msg.time,
        };
        this.updateSelecetUserListSate(data);
      }
      if (message.type === "0x45") {
        let msg = transMessage(message);
        if (message.content.actorId != this.ID) {
          //对方说的话
          if (this.meetingId != meeting.meetingId) {
            //添加未读图标
            const data = {
              type: "unread",
              meetingId: meeting.meetingId,
            };
            this.updateSelecetUserListSate(data);
          } else {
            const params = {
              type: 1,
              from: 1,
            };
            this.recieve = { ...msg, ...params };
          }
        } else {
          const params = {
            type: 1,
            from: 0,
          };
          this.recieve = { ...msg, ...params };
        }
        //添加最后一条消息
        const data = {
          type: "img",
          meetingId: meeting.meetingId,
          lastTxt: "【图片】",
          lastTime: msg.time,
        };
        this.updateSelecetUserListSate(data);
      }
      if (message.type === "0x58") {
        let msg = transCommentMessage(message);
        const params = {
          type: 4,
          from: 1,
        };
        this.recieve = { ...msg, ...params };
      }
      if (message.type === "0x76") {
        //验证成功
        let msg = transMessage(message);
        const params = {
          type: 5,
          from: 1,
        };
        this.recieve = { ...msg, ...params };
      }
      if (message.type === "0x77") {
        //验证成功
        let msg = transMessage(message);
        const params = {
          type: 5,
          from: 1,
        };
        this.recieve = { ...msg, ...params };
      }
      if (message.type === "0x62") {
        let msg = transLinkMessage(message);
        if (message.content.actorId != this.ID) {
          //对方说的话
          if (this.meetingId != meeting.meetingId) {
            //添加未读图标
            const data = {
              type: "unread",
              meetingId: meeting.meetingId,
            };
            this.updateSelecetUserListSate(data);
          } else {
            const params = {
              type: 3,
              from: 1,
            };
            this.recieve = { ...msg, ...params };
          }
        } else {
          const params = {
            type: 3,
            from: 0,
          };
          this.recieve = { ...msg, ...params };
        }
      }
      if (message.type === "0x75") {
        //用户的渠道消息
        const chanelMsg = {
          meetingId: meeting.meetingId,
          channel: message.content.word,
        };
        this.updateSelecetUserListSate({ type: "reset", ...chanelMsg });
      }
    },
    concatSmartMeeting(user) {
      const s = `?talkerType=${user.waiterType}&talkerId=${user.waiterId}&meetingId=${user.smallMeetingId}&oterId=${user.memberId}`;
      const meetingInstantce = new SmartMeeting(s, user.smallMeetingId); //创建一个小会场ws实例
      meetingInstantce.createWs(); //创建小会场ws
      meetingInstantce.wsTask.addEventListener("message", (e) => {
        this.onMessage(e, meetingInstantce);
      });
      // 将meeting实例放入store中
      const params = {
        type: "add",
        key: `ws${user.smallMeetingId}`,
        value: meetingInstantce,
      };
      this.updateMeeting(params); //更新metting列表
      const userInfo = {
        meetingId: user.smallMeetingId,
        offline: false,
        active: false,
        unread: 0,
        lastTxt: "",
        lastTime: "",
        memberId: user.memberId,
        nikeName: user.memberNikeName || "",
        userType: user.memberType,
        userPhone: user.userPhone || "",
        clientId: user.clientId,
      };
      if (userInfo.userType == "4") {
        //给游客设置名称
        const str = userInfo.memberId.slice(-4);
        userInfo.nikeName = "游客" + str;
      }
      this.updateSelecetUserList({ type: "add", ...userInfo }); // 更新选中的列表
      this.onlinComplete = true;
    },
  },
};
</script>

<style lang="scss" scoped>
.border-box {
  display: flex;
  align-items: center;
  height: 38px;
  width: 278px;
  border: 1px solid #e6e6e6;
  .limit-label {
    display: inline-block;
    text-align: center;
    flex: 0 0 120px;
    line-height: 36px;
    background: #fbfbfb;
    border-right: 1px solid #e6e6e6;
  }
  .limit-input {
    height: 100%;
    padding: 5px 10px;
    width: 100%;
  }
}
.conversition.el-row {
  display: flex;
  align-items: center;
}
.main-cover {
  display: flex;
  height: 630px;
}
.id-input {
  border: 1px solid #ccc;
  width: 100px;
  border-radius: 4px;
}
.inner-list {
  width: 270px;
  background-color: #fff;
  border: 1px solid #f2f2f2;
}
.chat-panel {
  flex: 1;
}
.right-menu {
  width: 340px;
  background-color: #fbfbfb;
  border: 1px solid #f2f2f2;
}
</style>